package com.knowledge.common.utils;

import java.io.*;

import com.knowledge.common.config.RuoYiConfig;
import com.knowledge.common.constant.Constants;
import org.apache.poi.hslf.usermodel.*;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.text.PDFTextStripper;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.xslf.usermodel.XMLSlideShow;
import org.apache.poi.xslf.usermodel.XSLFSlide;
import org.apache.poi.xslf.usermodel.XSLFTextShape;

/**
 * 文件解析工具类
 * 支持多种文件格式的内容提取
 *
 * @author knowledge
 */
public class FileParserUtils {

    /**
     * 根据文件类型解析文件内容
     *
     * @param filePath 文件路径
     * @param fileType 文件类型 (txt, pdf, docx, xls, xlsx, ppt, pptx)
     * @return 文件内容
     */
    public static String parseFile(String filePath, String fileType) throws IOException {
        // 将相对路径转换为绝对路径
        String absolutePath = getAbsolutePath(filePath);

        switch (fileType.toLowerCase()) {
            case "txt":
                return parseTxtFile(absolutePath);
            case "pdf":
                return parsePdfFile(absolutePath);
            case "docx":
                return parseDocxFile(absolutePath);
            case "xls":
            case "xlsx":
                return parseExcelFile(absolutePath);
            case "ppt":
                return parsePptFile(absolutePath);
            case "pptx":
                return parsePptxFile(absolutePath);
            default:
                throw new IllegalArgumentException("不支持的文件类型: " + fileType);
        }
    }

    /**
     * 将相对路径转换为绝对路径
     *
     * @param filePath 文件路径
     * @return 绝对路径
     */
    public static String getAbsolutePath(String filePath) {
        // 如果是相对路径，则转换为绝对路径
        if (filePath.startsWith(Constants.RESOURCE_PREFIX)) {
            // 去掉 /profile 前缀
            String relativePath = filePath.substring(Constants.RESOURCE_PREFIX.length() + 1);
            // 拼接基础路径
            return RuoYiConfig.getProfile() + File.separator + relativePath;
        }
        // 如果已经是绝对路径，直接返回
        return filePath;
    }

    /**
     * 解析TXT文件
     *
     * @param filePath 文件路径
     * @return 文件内容
     */
    public static String parseTxtFile(String filePath) throws IOException {
        StringBuilder content = new StringBuilder();
        try (BufferedReader reader = new BufferedReader(
                new InputStreamReader(new FileInputStream(filePath), "UTF-8"))) {
            String line;
            while ((line = reader.readLine()) != null) {
                content.append(line).append("\n");
            }
        }
        return content.toString();
    }

    /**
     * 解析PDF文件
     *
     * @param filePath 文件路径
     * @return 文件内容
     */
    public static String parsePdfFile(String filePath) throws IOException {
        try (PDDocument document = PDDocument.load(new File(filePath))) {
            PDFTextStripper stripper = new PDFTextStripper();
            return stripper.getText(document);
        }
    }

    /**
     * 解析DOCX文件
     *
     * @param filePath 文件路径
     * @return 文件内容
     */
    public static String parseDocxFile(String filePath) throws IOException {
        try (FileInputStream fis = new FileInputStream(filePath);
             XWPFDocument document = new XWPFDocument(fis)) {

            StringBuilder content = new StringBuilder();
            for (XWPFParagraph paragraph : document.getParagraphs()) {
                content.append(paragraph.getText()).append("\n");
            }
            return content.toString();
        }
    }

    /**
     * 解析Excel文件(XLS/XLSX)
     *
     * @param filePath 文件路径
     * @return 文件内容
     */
    public static String parseExcelFile(String filePath) throws IOException {
        StringBuilder content = new StringBuilder();

        try (FileInputStream fis = new FileInputStream(filePath);
             Workbook workbook = createWorkbook(fis, filePath)) {

            // 遍历所有工作表
            for (int i = 0; i < workbook.getNumberOfSheets(); i++) {
                Sheet sheet = workbook.getSheetAt(i);
                content.append("Sheet名称: ").append(sheet.getSheetName()).append("\n");

                // 遍历行
                for (Row row : sheet) {
                    // 遍历单元格
                    for (Cell cell : row) {
                        content.append(getCellValue(cell)).append("\t");
                    }
                    content.append("\n");
                }
                content.append("\n");
            }
        }

        return content.toString();
    }

    /**
     * 解析PPT文件
     *
     * @param filePath 文件路径
     * @return 文件内容
     */
    /**
     * 解析PPT文件
     *
     * @param filePath 文件路径
     * @return 文件内容
     */
    public static String parsePptFile(String filePath) throws IOException {
        StringBuilder content = new StringBuilder();

        try (FileInputStream fis = new FileInputStream(filePath);
             HSLFSlideShow slideshow = new HSLFSlideShow(fis)) {

            // 获取幻灯片
            int slideNumber = 1;
            for (HSLFSlide slide : slideshow.getSlides()) {
                content.append("Slide ").append(slideNumber).append(":\n");
                // 获取幻灯片中的形状
                for (var shape : slide.getShapes()) {
                    // 判断是否为文本形状
                    if (shape instanceof HSLFTextShape) {
                        HSLFTextShape textShape = (HSLFTextShape) shape;
                        // 遍历文本形状中的段落
                        for (HSLFTextParagraph paragraph : textShape.getTextParagraphs()) {
                            // 遍历段落中的文本运行，拼接文本
                            StringBuilder paraText = new StringBuilder();
                            for (HSLFTextRun run : paragraph.getTextRuns()) {
                                // 这里 run 的类型是 HSLFTextRun，应存在 getText() 方法
                                paraText.append(run.getRawText());
                            }
                            content.append(paraText).append("\n");
                        }
                    }
                }

                content.append("\n");
                slideNumber++;
            }
        }

        return content.toString();
    }

    /**
     * 解析PPTX文件
     *
     * @param filePath 文件路径
     * @return 文件内容
     */
    public static String parsePptxFile(String filePath) throws IOException {
        StringBuilder content = new StringBuilder();

        try (FileInputStream fis = new FileInputStream(filePath);
             XMLSlideShow slideshow = new XMLSlideShow(fis)) {

            // 获取幻灯片
            int slideIndex = 0;
            for (XSLFSlide slide : slideshow.getSlides()) {
                content.append("Slide ").append(slideIndex + 1).append(":\n");
                // 获取幻灯片中的文本
                for (var shape : slide.getShapes()) {
                    if (shape instanceof XSLFTextShape) {
                        content.append(((XSLFTextShape) shape).getText()).append("\n");
                    }
                }
                content.append("\n");
                slideIndex++;
            }
        }

        return content.toString();
    }

    /**
     * 根据文件扩展名创建相应的Workbook对象
     *
     * @param fis      文件输入流
     * @param filePath 文件路径
     * @return Workbook对象
     * @throws IOException IO异常
     */
    private static Workbook createWorkbook(FileInputStream fis, String filePath) throws IOException {
        if (filePath.toLowerCase().endsWith(".xlsx")) {
            return new XSSFWorkbook(fis);
        } else {
            return new HSSFWorkbook(fis);
        }
    }

    /**
     * 获取单元格的值
     *
     * @param cell 单元格
     * @return 单元格内容
     */
    private static String getCellValue(Cell cell) {
        if (cell == null) {
            return "";
        }

        switch (cell.getCellType()) {
            case STRING:
                return cell.getStringCellValue();
            case NUMERIC:
                if (DateUtil.isCellDateFormatted(cell)) {
                    return cell.getDateCellValue().toString();
                } else {
                    return String.valueOf(cell.getNumericCellValue());
                }
            case BOOLEAN:
                return String.valueOf(cell.getBooleanCellValue());
            case FORMULA:
                return cell.getCellFormula();
            default:
                return "";
        }
    }
}